# Copyright (C) 2025 Huawei Technologies Co., Ltd. All rights reserved.	

<# NOTE: openUBMC boot module Cmdlets #>

function Get-openUBMCBootupSequence {
<#
.SYNOPSIS
Query bios boot up device sequence.

.DESCRIPTION
Query bios boot up device sequence. Boot up device contains: Hdd, Cd, Pxe, Others.

.PARAMETER Session
openUBMC redfish session object which is created by Connect-openUBMC cmdlet.
A session object identifies an openUBMC server to which this cmdlet will be executed.

.OUTPUTS
Array[String[]]
Returns string array identifies boot up device in order if cmdlet executes successfully.
In case of an error or warning, exception will be returned.

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1 -Credential $credential -TrustCert
PS C:\> $Sequence = Get-openUBMCBootupSequence $session
PS C:\> $Sequence

Host           BootupSequence
----           --------------
192.168.1.1       {Pxe, HDD, Cd, Others}

PS C:\> $Sequence | fl

Host           : 192.168.1.1
BootupSequence : {Pxe, HDD, Cd, Others}

.LINK
https://gitcode.com/openUBMC/cmdlets_plugin

Set-openUBMCBootupSequence
Get-openUBMCBootSourceOverride
Set-openUBMCBootSourceOverride
Connect-openUBMC
Disconnect-openUBMC

#>
  [CmdletBinding()]
  param (
    [RedfishSession[]]
    [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
    $Session
  )

  begin {
  }

  process {
    Assert-ArrayNotNull $Session 'Session'

    $Logger.info("Invoke Get Bootup Sequence function")

    $ScriptBlock = {
      param($RedfishSession)
      $Path = "/redfish/v1/Systems/$($RedfishSession.Id)"
      $Response = $(Invoke-RedfishRequest $RedfishSession $Path | ConvertFrom-WebResponse)
      # V3
      if ($null -ne $Response.Oem.openUBMC.BootupSequence) {
        $Logger.info($(Trace-Session $RedfishSession "Find System.Oem.openUBMC.BootupSequence, return directly"))
        $Clone = New-Object PSObject
        $Clone | Add-Member -MemberType NoteProperty "BootupSequence" $Response.Oem.openUBMC.BootupSequence
        return $(Update-SessionAddress $RedfishSession $Clone)
      }
      else {
        # V5
        $Logger.info($(Trace-Session $RedfishSession "V5 BMC, will try get sequence from BIOS API"))
        $BiosPath = "$Path/Bios"
        $BiosResponse = $(Invoke-RedfishRequest $RedfishSession $BiosPath | ConvertFrom-WebResponse)
        $Attrs = $BiosResponse.Attributes
        $seq = New-Object System.Collections.ArrayList
        0..3 | ForEach-Object {
          $BootType = $Attrs."BootTypeOrder$_"
          [Void] $seq.Add($BMC.V52V3Mapping[$BootType])
        }

        $Clone = New-Object PSObject
        $Clone | Add-Member -MemberType NoteProperty "BootupSequence" $seq.ToArray()
        return $(Update-SessionAddress $RedfishSession $Clone)
      }
    }

    try {
      $tasks = New-Object System.Collections.ArrayList
      $pool = New-RunspacePool $Session.Count
      for ($idx = 0; $idx -lt $Session.Count; $idx++) {
        $RedfishSession = $Session[$idx]
        $Logger.info($(Trace-Session $RedfishSession "Submit Get Bootup Sequence task"))
        [Void] $tasks.Add($(Start-ScriptBlockThread $pool $ScriptBlock @($RedfishSession)))
      }

      $Results = Get-AsyncTaskResults $tasks
      return ,$Results
    }
    finally {
      Close-Pool $pool
    }
  }

  end {
  }
}


function Set-openUBMCBootupSequence {
<#
.SYNOPSIS
Set bios boot up device sequence.

.DESCRIPTION
Set bios boot up device sequence.
Boot up device contains: Hdd, Cd, Pxe, Others.
New boot up sequence settings take effect upon the next restart of the system.

.PARAMETER Session
openUBMC redfish session object which is created by Connect-openUBMC cmdlet.
A session object identifies an openUBMC server to which this cmdlet will be executed.

.PARAMETER BootSequence
A array set of boot device in order, should contains all available boot devices.
example: ,@('Hdd', 'Cd', 'Pxe', 'Others')

.OUTPUTS
None
Returns None if cmdlet executes successfully.
In case of an error or warning, exception will be returned.

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1 -Credential $credential -TrustCert
PS C:\> $BootUpSequence = ,@('Pxe', 'Hdd', 'Cd', 'Others')
PS C:\> Set-openUBMCBootupSequence $session $BootUpSequence

Set boot up device sequence for single openUBMC server

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1,192.168.1.3 -Credential $credential -TrustCert
PS C:\> $BootUpSequence = @(@('Pxe', 'Hdd', 'Cd', 'Others'), @('Cd', 'Pxe', 'Hdd', 'Others'))
PS C:\> Set-openUBMCBootupSequence $session $BootUpSequence

Set boot up device sequence for multiple openUBMC server


.LINK
https://gitcode.com/openUBMC/cmdlets_plugin

Get-openUBMCBootupSequence
Get-openUBMCBootSourceOverride
Set-openUBMCBootSourceOverride
Connect-openUBMC
Disconnect-openUBMC

#>
  [CmdletBinding()]
  param (
    [RedfishSession[]]
    [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
    $Session,

    [BootSequence[][]]
    [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)]
    $BootSequence
  )

  begin {
  }

  process {
    Assert-ArrayNotNull $Session 'Session'
    Assert-ArrayNotNull $BootSequence 'BootSequence'
    $BootSequenceList = Get-MatchedSizeArray $Session $BootSequence 'Session' 'BootSequence'
    # validate boot sequence input
    $BootSequenceList | ForEach-Object {
      if ($null -ne $_ -or $_.Count -eq 4) {
        $ValidSet = Get-EnumNames "BootSequence"
        $diff = Compare-Object $_ $ValidSet -PassThru
        if ($null -eq $diff) {
          return
        }
      }
      throw [String]::format($(Get-i18n "ERROR_ILLEGAL_BOOT_SEQ"), $_ -join ",")
    }

    $Logger.info("Invoke Set Bootup Sequence function")

    $ScriptBlock = {
      param($RedfishSession, $BootSequence)
      $Path = "/redfish/v1/Systems/$($RedfishSession.Id)"
      $Response = Invoke-RedfishRequest $RedfishSession $Path
      $System = $Response | ConvertFrom-WebResponse

      if ($null -ne $System.Oem.openUBMC.BootupSequence) {
        # V3
        $Logger.info($(Trace-Session $RedfishSession "[V3] Will set boot sequence using System resource"))
        $Payload = @{
          "Oem" = @{
            "openUBMC" = @{
              "BootupSequence" = $BootSequence;
            } | Resolve-EnumValues;
          };
        }

        $Logger.info($(Trace-Session $RedfishSession "Sending payload: $($Payload | ConvertTo-Json -Depth 5)"))
        $Headers = @{'If-Match' = $Response.Headers.get('ETag'); }
        Invoke-RedfishRequest $RedfishSession $Path 'PATCH' $Payload $Headers | Out-Null
        return $null
      }
      else {
        # V5
        $Logger.info($(Trace-Session $RedfishSession "[V5] Will set boot sequence using BIOS settings resource"))
        $SetBiosPath = "$Path/Bios/Settings"
        $V5BootSequence = @{}
        for ($idx = 0; $idx -lt $BootSequence.Count; $idx++) {
          $BootType = $BMC.V32V5Mapping[$BootSequence[$idx].toString()]
          $V5BootSequence."BootTypeOrder$idx" = $BootType
        }
        $Logger.info($(Trace-Session $RedfishSession "[V5] Boot device sequence: $V5BootSequence"))
        $Payload = @{"Attributes" = $V5BootSequence; }
        $Logger.info($(Trace-Session $RedfishSession "Sending payload: $($Payload | ConvertTo-Json -Depth 5)"))
        Invoke-RedfishRequest $RedfishSession $SetBiosPath 'PATCH' $Payload | Out-Null
        return $null
      }
    }

    try {
      $tasks = New-Object System.Collections.ArrayList
      $pool = New-RunspacePool $Session.Count
      for ($idx = 0; $idx -lt $Session.Count; $idx++) {
        $RedfishSession = $Session[$idx]
        $Parameters = @($RedfishSession, $BootSequenceList[$idx])
        $Logger.info($(Trace-Session $RedfishSession "Submit Get Bootup Sequence task"))
        [Void] $tasks.Add($(Start-ScriptBlockThread $pool $ScriptBlock $Parameters))
      }

      $Results = Get-AsyncTaskResults $tasks
      return ,$Results
    }
    finally {
      Close-Pool $pool
    }
  }

  end {
  }
}


function Get-openUBMCBootSourceOverride {
<#
.SYNOPSIS
Query bios boot source override target, enable status, mode.

.DESCRIPTION
Query bios boot source override target, enable status, mode.

.PARAMETER Session
openUBMC redfish session object which is created by Connect-openUBMC cmdlet.
A session object identifies an openUBMC server to which this cmdlet will be executed.

.OUTPUTS
String[]
Returns bios boot source override target if cmdlet executes successfully.
In case of an error or warning, exception will be returned.

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1 -Credential $credential -TrustCert
PS C:\> $BootSourceOverride = Get-openUBMCBootSourceOverride $session
PS C:\> $BootSourceOverride

Host         BootSourceOverrideTarget BootSourceOverrideEnabled BootSourceOverrideMode
----         ------------------------ ------------------------- ----------------------
192.168.1.1     None                     Disabled                  UEFI


PS C:\> $BootSourceOverride | fl

Host                      : 192.168.1.1
BootSourceOverrideTarget  : None
BootSourceOverrideEnabled : Disabled
BootSourceOverrideMode    : UEFI

.LINK
https://gitcode.com/openUBMC/cmdlets_plugin

Get-openUBMCBootupSequence
Set-openUBMCBootupSequence
Set-openUBMCBootSourceOverride
Connect-openUBMC
Disconnect-openUBMC

#>
  [CmdletBinding()]
  param (
    [RedfishSession[]]
    [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
    $Session
  )

  begin {
  }

  process {
    Assert-ArrayNotNull $Session 'Session'

    $Logger.info("Invoke Get Boot Source Override function")

    $ScriptBlock = {
      param($RedfishSession)
      $(Get-Logger).info($(Trace-Session $RedfishSession "Get boot source override now"))
      $Path = "/redfish/v1/Systems/$($RedfishSession.Id)"
      $Response = $(Invoke-RedfishRequest $RedfishSession $Path | ConvertFrom-WebResponse)
      $Properties = @(
        "BootSourceOverrideTarget", "BootSourceOverrideEnabled", "BootSourceOverrideMode"
      )
      $BootSourceOverride = Copy-ObjectProperties $Response.Boot $Properties
      return $(Update-SessionAddress $RedfishSession $BootSourceOverride)
    }

    try {
      $tasks = New-Object System.Collections.ArrayList
      $pool = New-RunspacePool $Session.Count
      for ($idx = 0; $idx -lt $Session.Count; $idx++) {
        $RedfishSession = $Session[$idx]
        $Logger.info($(Trace-Session $RedfishSession "Submit Get Boot Source Override task"))
        [Void] $tasks.Add($(Start-ScriptBlockThread $pool $ScriptBlock @($RedfishSession)))
      }

      $Results = Get-AsyncTaskResults $tasks
      return ,$Results
    }
    finally {
      Close-Pool $pool
    }
  }

  end {
  }
}


function Set-openUBMCBootSourceOverride {
<#
.SYNOPSIS
Modify bios boot source override target, enable status and mode.

.DESCRIPTION
Modify bios boot source override target, enable status and mode.
This boot source override target takes effect upon the next restart of the system.

.PARAMETER Session
openUBMC redfish session object which is created by Connect-openUBMC cmdlet.
A session object identifies an openUBMC server to which this cmdlet will be executed.

.PARAMETER BootSourceOverrideTarget
BootSourceOverrideTarget specifies the bios boot source override target
Available boot source override target: 'None', 'Pxe', 'Floppy', 'Cd', 'Hdd', 'BiosSetup'.

.PARAMETER BootSourceOverrideEnabled
BootSourceOverrideEnabled specifies the bios boot source override enable status
Available boot source override enable status: 'Disabled', 'Once', 'Continuous'.

.PARAMETER BootSourceOverrideMode
BootSourceOverrideMode specifies the bios boot source override mode
Available boot source override mode: 'Legacy', 'UEFI'.

.OUTPUTS
Null
Returns Null if cmdlet executes successfully.
In case of an error or warning, exception will be returned.

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1 -Credential $credential -TrustCert
PS C:\> Set-openUBMCBootSourceOverride $session 'Pxe' 'Once' 'UEFI'

Set boot source override target for single openUBMC server

.EXAMPLE

PS C:\> $credential = Get-Credential
PS C:\> $session = Connect-openUBMC -Address 192.168.1.1,192.168.1.5 -Credential $credential -TrustCert
PS C:\> Set-openUBMCBootSourceOverride -Session $session -BootSourceOverrideTarget Pxe `
          -BootSourceOverrideEnabled Once -BootSourceOverrideMode UEFI

Set boot source override target for multiple openUBMC server


.LINK
https://gitcode.com/openUBMC/cmdlets_plugin

Get-openUBMCBootupSequence
Set-openUBMCBootupSequence
Get-openUBMCBootSourceOverride
Connect-openUBMC
Disconnect-openUBMC

#>
  [CmdletBinding()]
  param (
    [RedfishSession[]]
    [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
    $Session,

    [BootSourceOverrideTarget[]]
    [parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)]
    $BootSourceOverrideTarget,

    [BootSourceOverrideEnabled[]]
    [parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 2)]
    $BootSourceOverrideEnabled,

    [BootSourceOverrideMode[]]
    [parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 3)]
    $BootSourceOverrideMode
  )

  begin {
  }

  process {
    Assert-ArrayNotNull $Session 'Session'

    $BootSourceOverrideTargetList = Get-OptionalMatchedSizeArray $Session $BootSourceOverrideTarget
    $BootSourceOverrideEnabledList = Get-OptionalMatchedSizeArray $Session $BootSourceOverrideEnabled
    $BootSourceOverrideModeList = Get-OptionalMatchedSizeArray $Session $BootSourceOverrideMode

    $Logger.info("Invoke Set Boot Source Override function")

    $ScriptBlock = {
      param($RedfishSession, $Payload)
      $(Get-Logger).info($(Trace-Session $RedfishSession "Set boot source override now"))
      $Path = "/redfish/v1/Systems/$($RedfishSession.Id)"
      
      $Logger.info($(Trace-Session $RedfishSession "Sending payload: $($Payload | ConvertTo-Json)"))
      Invoke-RedfishRequest $RedfishSession $Path 'PATCH' $Payload | Out-Null
      return $null
    }

    try {
      $tasks = New-Object System.Collections.ArrayList
      $pool = New-RunspacePool $Session.Count
      for ($idx = 0; $idx -lt $Session.Count; $idx++) {
        $RedfishSession = $Session[$idx]
        $BootPayload = @{
            "BootSourceOverrideTarget" = $BootSourceOverrideTargetList[$idx];
            "BootSourceOverrideEnabled" = $BootSourceOverrideEnabledList[$idx];
            "BootSourceOverrideMode" = $BootSourceOverrideModeList[$idx]   
        } | Remove-EmptyValues | Resolve-EnumValues

        if ($BootPayload.Count -eq 0) {
            throw $(Get-i18n ERROR_NO_UPDATE_PAYLOAD)
        }

        $Payload = @{}
        $Payload.Boot = $BootPayload

        $Parameters = @($RedfishSession, $Payload)
        $Logger.info($(Trace-Session $RedfishSession "Submit Set Boot source override target task"))
        [Void] $tasks.Add($(Start-ScriptBlockThread $pool $ScriptBlock $Parameters))
      }

      $Results = Get-AsyncTaskResults $tasks
      return ,$Results
    }
    finally {
      Close-Pool $pool
    }
  }

  end {
  }
}
